package redis

import (
	"github.com/gomodule/redigo/redis"
)

func (k *key) Publish(channel string, value any) IntResult {
	return k.cmd("PUBLISH", channel, value)
}

type Subscriber struct {
	c        *redis.PubSubConn
	channels map[string]bool
	patterns map[string]bool
}

func (k *key) Subscriber() *Subscriber {
	return &Subscriber{c: &redis.PubSubConn{Conn: k.c.pool.Get()}, channels: map[string]bool{}, patterns: map[string]bool{}}
}

func (r *Subscriber) Subscribe(channel ...string) error {
	return r.c.Subscribe(strs2ifs(channel)...)
}

func (r *Subscriber) PSubscribe(pattern ...string) error {
	return r.c.PSubscribe(strs2ifs(pattern)...)
}

func (r *Subscriber) Unsubscribe(channel ...string) error {
	return r.c.Unsubscribe(strs2ifs(channel)...)
}

func (r *Subscriber) PUnsubscribe(pattern ...string) error {
	return r.c.PUnsubscribe(strs2ifs(pattern)...)
}

// 退订至0时终止接收并关闭连接
// 这是因为在Receive等待数据的时候调用Close会报错或者卡住
func (r *Subscriber) Receive(fn func(string, []byte)) error {
	defer r.c.Close()
	for {
		switch v := r.c.Receive().(type) {
		case redis.Message:
			ch := v.Channel
			if ch == "" {
				ch = v.Pattern
			}
			fn(ch, v.Data)
		case redis.Subscription:
			switch v.Kind {
			case "subscribe":
				r.channels[v.Channel] = true
			case "psubscribe":
				r.patterns[v.Channel] = true
			case "unsubscribe":
				delete(r.channels, v.Channel)
			case "punsubscribe":
				delete(r.patterns, v.Channel)
			}
			if v.Count == 0 {
				return nil
			}
		case error:
			return v
		}
	}
}

func strs2ifs(ss []string) []any {
	ifs := make([]any, len(ss))
	for i, s := range ss {
		ifs[i] = s
	}
	return ifs
}
